﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using HtmlAgilityPack;
using PMC;
using PMC.Interfaces;
using PMC.Plugins;
using PMC.Scripts;
using System.Web;
using PMC.Structs;
using mshtml;
using System.Globalization;

namespace CashCrusaderScript
{
    [ScriptInfo("CashCrusader", "Martijn Lentink", "Script voor websites met een CashCrusader-script", "2.0", "nl")]
    [ScriptInfo("CashCrusader", "Martijn Lentink", "Script for sites with a CashCrusader-script", "2.0", "en")]
    public class CashCrusader : Script
    {
        private static readonly Dictionary<string, List<string>> PreviousLinks = new Dictionary<string, List<string>>();
        public override HtmlDocumentHandler Handle(IWbrowser webBrowser)
        {
            var cookies = webBrowser.GetCookies();
            // Checks if login action is required
            if (!Webpage.IsLoggedIn(webBrowser.Document, cookies))
            {
                Webpage.PerformLogin(webBrowser.CurrentWebsite, Convert.ToString(webBrowser.Url, CultureInfo.InvariantCulture));
                return new HtmlDocumentHandler(DocumentHandler.Reload);
            }

            // Checks if the page has already been credited
            if (Webpage.IsAlreadyCredited(webBrowser))
                return new HtmlDocumentHandler(DocumentHandler.Skip);

            Uri replaceUrl; 
            if (Webpage.SkipAdminMessage(webBrowser, out replaceUrl))
                return new HtmlDocumentHandler(DocumentHandler.Replace, replaceUrl);

            #region Captcha
            
            // Loops through all images in search for captcha's, then decode it and replace all &amp; with & etc.
            var images =  webBrowser.Document.DocumentNode.Descendants("img")
                    .Select(e => HttpUtility.HtmlDecode(e.GetAttributeValue("src", string.Empty)))
                    .Where(s => s.Contains("runner.php?TN="));

            // If we found two images, then we need so solve them.
            if (images.Count() == 2)
            {
                Dictionary<string, Uri> captchaAnswerLinks = new Dictionary<string, Uri>(5);
                foreach (HtmlNode link in webBrowser.Document.DocumentNode.Descendants("a"))
                {
                    var att = HttpUtility.HtmlDecode(link.GetAttributeValue("href", string.Empty));
                    if (Regex.IsMatch(att, @"runner.php\?KE=[a-z]{8}&PI=\d{4}&[A-Z]{2}="))
                        captchaAnswerLinks.Add(link.InnerHtml, new Uri(webBrowser.Url, att));
                }

                // Downloads the images by using the URL's
                var firstLink = images.ElementAt(0);
                var secondLink = images.ElementAt(1);
                var firstImage = Global.HtmlUtility.ImageFromUrl(new Uri(firstLink));
                var secondImage = Global.HtmlUtility.ImageFromUrl(new Uri(secondLink));

                // Get KE-hash from link, any link will do but we'll use firstLink here.
                var parsedQuery = HttpUtility.ParseQueryString(firstLink);
                var keHash = parsedQuery["KE"];
                if (keHash != null && !PreviousLinks.ContainsKey(keHash))
                    PreviousLinks.Add(keHash, new List<string>(5));
                var currentHash = keHash != null ? PreviousLinks[keHash] : null;

                // Checks if both the images are correct
                if (firstImage != null && secondImage != null)
                {
                    String solution;
                    // Create CAPTCHA-objects and wrap them in a using since their bitmap images
                    using (var firstCaptchaImage = new CaptchaImage(firstImage))
                    {
                        using (var secondCaptchaImage = new CaptchaImage(secondImage))
                        {
                            // Gets the solutions of both the images and creates a new string.
                            solution = firstCaptchaImage.GetSolution() + secondCaptchaImage.GetSolution();
                        }
                    }

                    //Todo: maybe add position check. So when multiple keys have the same num_match check the best is chosen by the one that has the most digits on the correct position!
                    // All answers should be 4 digits
                    //if (solution.Length == 4)
                    {
                        Uri captchaSolutionUrl = null;
                        // Check if the solution is in link list
                        if (!captchaAnswerLinks.ContainsKey(solution))
                        {
                            // Remove previous tried solutions to smaller the scope upon fail
                            if (currentHash != null)
                            {
                                foreach (var key in currentHash)
                                    captchaAnswerLinks.Remove(key);
                            }
                            // Start guessing the solution by picking the best match
                            int bestMatch = 0;
                            string bestKey = string.Empty;
                            // Loop through every key (possible solution)
                            foreach (string key in captchaAnswerLinks.Keys)
                            {
                                int numMatch = 0;
                                foreach (char keyChar in key)
                                {
                                    foreach (char solutionChar in solution)
                                    {
                                        // Compare every character, if it matches it means that both are the same digit.
                                        if (keyChar == solutionChar)
                                            numMatch++;
                                    }
                                }
                                if (numMatch > bestMatch)
                                {
                                    bestKey = key;
                                    bestMatch = numMatch;
                                }
                            }
                            // Add this key to the hashlist, so we know that this solution has already been used
                            if (currentHash != null)
                                currentHash.Add(bestKey);
                            captchaSolutionUrl = captchaAnswerLinks[bestKey];
                        }
                            // Solution is correct, lets grab that link!
                        else
                        {
                            captchaSolutionUrl = captchaAnswerLinks[solution];
                        }

                        return new HtmlDocumentHandler(DocumentHandler.Replace, captchaSolutionUrl);
                    }

                        //// Loop through all the anchors and check if a anchor contains the captcha-code
                    //// If one is found, navigate to this one to solve it!
                    //foreach (var link in webBrowser.Document.DocumentNode.Descendants("a"))
                    //{
                    //    String href = link.GetAttributeValue("href", string.Empty);
                    //    if (href.IndexOf(solution, StringComparison.Ordinal) > -1 && href.Length == 4) // Does it really contain the code?
                    //        return new HtmlDocumentHandler(DocumentHandler.Replace, new Uri(webBrowser.Url, href));
                    //}
                }
            }
            #endregion

            // Wait for the interval
            return new HtmlDocumentHandler();
        }

        public override void Login(Website website, string path = null)
        {
            Webpage.PerformLogin(website, path);
        }
    }
}
